/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef vm_NativeObject_h#define vm_NativeObject_h#include"mozilla/Assertions.h"#include"mozilla/Attributes.h"#include<stdint.h>#include"jsfriendapi.h"#include"jsobj.h"#include"NamespaceImports.h"#include"gc/Barrier.h"#include"gc/Heap.h"#include"gc/Marking.h"#include"js/Value.h"#include"vm/Shape.h"#include"vm/ShapedObject.h"#include"vm/String.h"#include"vm/TypeInference.h"namespacejs{classShape;classTenuringTracer;/* * To really poison a set of values, using 'magic' or 'undefined' isn't good * enough since often these will just be ignored by buggy code (see bug 629974) * in debug builds and crash in release builds. Instead, we use a safe-for-crash * pointer. */staticMOZ_ALWAYS_INLINEvoidDebug_SetValueRangeToCrashOnTouch(Value*beg,Value*end){#ifdef DEBUGfor(Value*v=beg;v!=end;++v)v->setObject(*reinterpret_cast<JSObject*>(0x48));#endif}staticMOZ_ALWAYS_INLINEvoidDebug_SetValueRangeToCrashOnTouch(Value*vec,size_tlen){#ifdef DEBUGDebug_SetValueRangeToCrashOnTouch(vec,vec+len);#endif}staticMOZ_ALWAYS_INLINEvoidDebug_SetValueRangeToCrashOnTouch(GCPtrValue*vec,size_tlen){#ifdef DEBUGDebug_SetValueRangeToCrashOnTouch((Value*)vec,len);#endif}staticMOZ_ALWAYS_INLINEvoidDebug_SetSlotRangeToCrashOnTouch(HeapSlot*vec,uint32_tlen){#ifdef DEBUGDebug_SetValueRangeToCrashOnTouch((Value*)vec,len);#endif}staticMOZ_ALWAYS_INLINEvoidDebug_SetSlotRangeToCrashOnTouch(HeapSlot*begin,HeapSlot*end){#ifdef DEBUGDebug_SetValueRangeToCrashOnTouch((Value*)begin,end-begin);#endif}classArrayObject;/* * ES6 20130308 draft 8.4.2.4 ArraySetLength. * * |id| must be "length", |attrs| are the attributes to be used for the newly- * changed length property, |value| is the value for the new length, and * |result| receives an error code if the change is invalid. */externboolArraySetLength(JSContext*cx,Handle<ArrayObject*>obj,HandleIdid,unsignedattrs,HandleValuevalue,ObjectOpResult&result);/* * Elements header used for native objects. The elements component of such objects * offers an efficient representation for all or some of the indexed properties * of the object, using a flat array of Values rather than a shape hierarchy * stored in the object's slots. This structure is immediately followed by an * array of elements, with the elements member in an object pointing to the * beginning of that array (the end of this structure). * See below for usage of this structure. * * The sets of properties represented by an object's elements and slots * are disjoint. The elements contain only indexed properties, while the slots * can contain both named and indexed properties; any indexes in the slots are * distinct from those in the elements. If isIndexed() is false for an object, * all indexed properties (if any) are stored in the dense elements. * * Indexes will be stored in the object's slots instead of its elements in * the following case: * - there are more than MIN_SPARSE_INDEX slots total and the load factor * (COUNT / capacity) is less than 0.25 * - a property is defined that has non-default property attributes. * * We track these pieces of metadata for dense elements: * - The length property as a uint32_t, accessible for array objects with * ArrayObject::{length,setLength}(). This is unused for non-arrays. * - The number of element slots (capacity), gettable with * getDenseCapacity(). * - The array's initialized length, accessible with * getDenseInitializedLength(). * * Holes in the array are represented by MagicValue(JS_ELEMENTS_HOLE) values. * These indicate indexes which are not dense properties of the array. The * property may, however, be held by the object's properties. * * The capacity and length of an object's elements are almost entirely * unrelated! In general the length may be greater than, less than, or equal * to the capacity. The first case occurs with |new Array(100)|. The length * is 100, but the capacity remains 0 (indices below length and above capacity * must be treated as holes) until elements between capacity and length are * set. The other two cases are common, depending upon the number of elements * in an array and the underlying allocator used for element storage. * * The only case in which the capacity and length of an object's elements are * related is when the object is an array with non-writable length. In this * case the capacity is always less than or equal to the length. This permits * JIT code to optimize away the check for non-writable length when assigning * to possibly out-of-range elements: such code already has to check for * |index < capacity|, and fallback code checks for non-writable length. * * The initialized length of an object specifies the number of elements that * have been initialized. All elements above the initialized length are * holes in the object, and the memory for all elements between the initialized * length and capacity is left uninitialized. The initialized length is some * value less than or equal to both the object's length and the object's * capacity. * * There is flexibility in exactly the value the initialized length must hold, * e.g. if an array has length 5, capacity 10, completely empty, it is valid * for the initialized length to be any value between zero and 5, as long as * the in memory values below the initialized length have been initialized with * a hole value. However, in such cases we want to keep the initialized length * as small as possible: if the object is known to have no hole values below * its initialized length, then it is "packed" and can be accessed much faster * by JIT code. * * Elements do not track property creation order, so enumerating the elements * of an object does not necessarily visit indexes in the order they were * created. * * Shifted elements * ---------------- * It's pretty common to use an array as a queue, like this: * * while (arr.length > 0) * foo(arr.shift()); * * To ensure we don't get quadratic behavior on this, elements can be 'shifted' * in memory. tryShiftDenseElements does this by incrementing elements_ to point * to the next element and moving the ObjectElements header in memory (so it's * stored where the shifted Value used to be). * * Shifted elements can be moved when we grow the array, when the array is * frozen (for simplicity, shifted elements are not supported on objects that * are frozen, have copy-on-write elements, or on arrays with non-writable * length). */classObjectElements{public:enumFlags:uint16_t{// Integers written to these elements must be converted to doubles.CONVERT_DOUBLE_ELEMENTS=0x1,// Present only if these elements correspond to an array with// non-writable length; never present for non-arrays.NONWRITABLE_ARRAY_LENGTH=0x2,// These elements are shared with another object and must be copied// before they can be changed. A pointer to the original owner of the// elements, which is immutable, is stored immediately after the// elements data. There is one case where elements can be written to// before being copied: when setting the CONVERT_DOUBLE_ELEMENTS flag// the shared elements may change (from ints to doubles) without// making a copy first.COPY_ON_WRITE=0x4,// For TypedArrays only: this TypedArray's storage is mapping shared// memory. This is a static property of the TypedArray, set when it// is created and never changed.SHARED_MEMORY=0x8,// These elements are set to integrity level "frozen".FROZEN=0x10,};// The flags word stores both the flags and the number of shifted elements.// Allow shifting 2047 elements before actually moving the elements.staticconstsize_tNumShiftedElementsBits=11;staticconstsize_tMaxShiftedElements=(1<<NumShiftedElementsBits)-1;staticconstsize_tNumShiftedElementsShift=32-NumShiftedElementsBits;staticconstsize_tFlagsMask=(1<<NumShiftedElementsShift)-1;static_assert(MaxShiftedElements==2047,"MaxShiftedElements should match the comment");private:friendclass::JSObject;friendclassArrayObject;friendclassNativeObject;friendclassTenuringTracer;friendbooljs::SetIntegrityLevel(JSContext*cx,HandleObjectobj,IntegrityLevellevel);friendboolArraySetLength(JSContext*cx,Handle<ArrayObject*>obj,HandleIdid,unsignedattrs,HandleValuevalue,ObjectOpResult&result);// The NumShiftedElementsBits high bits of this are used to store the// number of shifted elements, the other bits are available for the flags.// See Flags enum above.uint32_tflags;/* * Number of initialized elements. This is <= the capacity, and for arrays * is <= the length. Memory for elements above the initialized length is * uninitialized, but values between the initialized length and the proper * length are conceptually holes. */uint32_tinitializedLength;/* Number of allocated slots. */uint32_tcapacity;/* 'length' property of array objects, unused for other objects. */uint32_tlength;boolshouldConvertDoubleElements()const{returnflags&CONVERT_DOUBLE_ELEMENTS;}voidsetShouldConvertDoubleElements(){// Note: allow isCopyOnWrite() here, see comment above.flags|=CONVERT_DOUBLE_ELEMENTS;}voidclearShouldConvertDoubleElements(){MOZ_ASSERT(!isCopyOnWrite());flags&=~CONVERT_DOUBLE_ELEMENTS;}boolhasNonwritableArrayLength()const{returnflags&NONWRITABLE_ARRAY_LENGTH;}voidsetNonwritableArrayLength(){// See ArrayObject::setNonWritableLength.MOZ_ASSERT(capacity==initializedLength);MOZ_ASSERT(numShiftedElements()==0);MOZ_ASSERT(!isCopyOnWrite());flags|=NONWRITABLE_ARRAY_LENGTH;}boolisCopyOnWrite()const{returnflags©_ON_WRITE;}voidclearCopyOnWrite(){MOZ_ASSERT(isCopyOnWrite());flags&=~COPY_ON_WRITE;}voidaddShiftedElements(uint32_tcount){MOZ_ASSERT(count<capacity);MOZ_ASSERT(count<initializedLength);MOZ_ASSERT(!(flags&(NONWRITABLE_ARRAY_LENGTH|FROZEN|COPY_ON_WRITE)));uint32_tnumShifted=numShiftedElements()+count;MOZ_ASSERT(numShifted<=MaxShiftedElements);flags=(numShifted<<NumShiftedElementsShift)|(flags&FlagsMask);capacity-=count;initializedLength-=count;}voidunshiftShiftedElements(uint32_tcount){MOZ_ASSERT(count>0);MOZ_ASSERT(!(flags&(NONWRITABLE_ARRAY_LENGTH|FROZEN|COPY_ON_WRITE)));uint32_tnumShifted=numShiftedElements();MOZ_ASSERT(count<=numShifted);numShifted-=count;flags=(numShifted<<NumShiftedElementsShift)|(flags&FlagsMask);capacity+=count;initializedLength+=count;}voidclearShiftedElements(){flags&=FlagsMask;MOZ_ASSERT(numShiftedElements()==0);}public:constexprObjectElements(uint32_tcapacity,uint32_tlength):flags(0),initializedLength(0),capacity(capacity),length(length){}enumclassSharedMemory{IsShared};constexprObjectElements(uint32_tcapacity,uint32_tlength,SharedMemoryshmem):flags(SHARED_MEMORY),initializedLength(0),capacity(capacity),length(length){}HeapSlot*elements(){returnreinterpret_cast<HeapSlot*>(uintptr_t(this)+sizeof(ObjectElements));}constHeapSlot*elements()const{returnreinterpret_cast<constHeapSlot*>(uintptr_t(this)+sizeof(ObjectElements));}staticObjectElements*fromElements(HeapSlot*elems){returnreinterpret_cast<ObjectElements*>(uintptr_t(elems)-sizeof(ObjectElements));}boolisSharedMemory()const{returnflags&SHARED_MEMORY;}GCPtrNativeObject&ownerObject()const{MOZ_ASSERT(isCopyOnWrite());return*(GCPtrNativeObject*)(&elements()[initializedLength]);}staticintoffsetOfFlags(){returnint(offsetof(ObjectElements,flags))-int(sizeof(ObjectElements));}staticintoffsetOfInitializedLength(){returnint(offsetof(ObjectElements,initializedLength))-int(sizeof(ObjectElements));}staticintoffsetOfCapacity(){returnint(offsetof(ObjectElements,capacity))-int(sizeof(ObjectElements));}staticintoffsetOfLength(){returnint(offsetof(ObjectElements,length))-int(sizeof(ObjectElements));}staticboolConvertElementsToDoubles(JSContext*cx,uintptr_telements);staticboolMakeElementsCopyOnWrite(JSContext*cx,NativeObject*obj);staticboolFreezeElements(JSContext*cx,HandleNativeObjectobj);boolisFrozen()const{returnflags&FROZEN;}voidfreeze(){MOZ_ASSERT(!isFrozen());MOZ_ASSERT(!isCopyOnWrite());flags|=FROZEN;}uint8_telementAttributes()const{if(isFrozen())returnJSPROP_ENUMERATE|JSPROP_PERMANENT|JSPROP_READONLY;returnJSPROP_ENUMERATE;}uint32_tnumShiftedElements()const{uint32_tnumShifted=flags>>NumShiftedElementsShift;MOZ_ASSERT_IF(numShifted>0,!(flags&(NONWRITABLE_ARRAY_LENGTH|FROZEN|COPY_ON_WRITE)));returnnumShifted;}uint32_tnumAllocatedElements()const{returnVALUES_PER_HEADER+capacity+numShiftedElements();}// This is enough slots to store an object of this class. See the static// assertion below.staticconstsize_tVALUES_PER_HEADER=2;};static_assert(ObjectElements::VALUES_PER_HEADER*sizeof(HeapSlot)==sizeof(ObjectElements),"ObjectElements doesn't fit in the given number of slots");/* * Shared singletons for objects with no elements. * emptyObjectElementsShared is used only for TypedArrays, when the TA * maps shared memory. */externHeapSlot*constemptyObjectElements;externHeapSlot*constemptyObjectElementsShared;structClass;classGCMarker;classShape;classNewObjectCache;// Operations which change an object's dense elements can either succeed, fail,// or be unable to complete. For native objects, the latter is used when the// object's elements must become sparse instead. The enum below is used for// such operations, and for similar operations on unboxed arrays and methods// that work on both kinds of objects.enumclassDenseElementResult{Failure,Success,Incomplete};/* * NativeObject specifies the internal implementation of a native object. * * Native objects use ShapedObject::shape_ to record property information. Two * native objects with the same shape are guaranteed to have the same number of * fixed slots. * * Native objects extend the base implementation of an object with storage for * the object's named properties and indexed elements. * * These are stored separately from one another. Objects are followed by a * variable-sized array of values for inline storage, which may be used by * either properties of native objects (fixed slots), by elements (fixed * elements), or by other data for certain kinds of objects, such as * ArrayBufferObjects and TypedArrayObjects. * * Named property storage can be split between fixed slots and a dynamically * allocated array (the slots member). For an object with N fixed slots, shapes * with slots [0..N-1] are stored in the fixed slots, and the remainder are * stored in the dynamic array. If all properties fit in the fixed slots, the * 'slots_' member is nullptr. * * Elements are indexed via the 'elements_' member. This member can point to * either the shared emptyObjectElements and emptyObjectElementsShared singletons, * into the inline value array (the address of the third value, to leave room * for a ObjectElements header;in this case numFixedSlots() is zero) or to * a dynamically allocated array. * * Slots and elements may both be non-empty. The slots may be either names or * indexes; no indexed property will be in both the slots and elements. */classNativeObject:publicShapedObject{protected:/* Slots for object properties. */js::HeapSlot*slots_;/* Slots for object dense elements. */js::HeapSlot*elements_;friendclass::JSObject;private:staticvoidstaticAsserts(){static_assert(sizeof(NativeObject)==sizeof(JSObject_Slots0),"native object size must match GC thing size");static_assert(sizeof(NativeObject)==sizeof(shadow::Object),"shadow interface must match actual implementation");static_assert(sizeof(NativeObject)%sizeof(Value)==0,"fixed slots after an object must be aligned");static_assert(offsetof(NativeObject,group_)==offsetof(shadow::Object,group),"shadow type must match actual type");static_assert(offsetof(NativeObject,slots_)==offsetof(shadow::Object,slots),"shadow slots must match actual slots");static_assert(offsetof(NativeObject,elements_)==offsetof(shadow::Object,_1),"shadow placeholder must match actual elements");static_assert(MAX_FIXED_SLOTS<=Shape::FIXED_SLOTS_MAX,"verify numFixedSlots() bitfield is big enough");static_assert(sizeof(NativeObject)+MAX_FIXED_SLOTS*sizeof(Value)==JSObject::MAX_BYTE_SIZE,"inconsistent maximum object size");}public:Shape*lastProperty()const{MOZ_ASSERT(shape_);returnshape_;}uint32_tpropertyCount()const{returnlastProperty()->entryCount();}boolhasShapeTable()const{returnlastProperty()->hasTable();}HeapSlotArraygetDenseElements(){returnHeapSlotArray(elements_,!getElementsHeader()->isCopyOnWrite());}HeapSlotArraygetDenseElementsAllowCopyOnWrite(){// Backdoor allowing direct access to copy on write elements.returnHeapSlotArray(elements_,true);}constValue&getDenseElement(uint32_tidx)const{MOZ_ASSERT(idx<getDenseInitializedLength());returnelements_[idx];}boolcontainsDenseElement(uint32_tidx){returnidx<getDenseInitializedLength()&&!elements_[idx].isMagic(JS_ELEMENTS_HOLE);}uint32_tgetDenseInitializedLength()const{returngetElementsHeader()->initializedLength;}uint32_tgetDenseCapacity()const{returngetElementsHeader()->capacity;}boolisSharedMemory()const{returngetElementsHeader()->isSharedMemory();}// Update the last property, keeping the number of allocated slots in sync// with the object's new slot span.MOZ_ALWAYS_INLINEboolsetLastProperty(JSContext*cx,Shape*shape);// As for setLastProperty(), but allows the number of fixed slots to// change. This can only be used when fixed slots are being erased from the// object, and only when the object will not require dynamic slots to cover// the new properties.voidsetLastPropertyShrinkFixedSlots(Shape*shape);// As for setLastProperty(), but changes the class associated with the// object to a non-native one. This leaves the object with a type and shape// that are (temporarily) inconsistent.voidsetLastPropertyMakeNonNative(Shape*shape);// As for setLastProperty(), but changes the class associated with the// object to a native one. The object's type has already been changed, and// this brings the shape into sync with it.voidsetLastPropertyMakeNative(JSContext*cx,Shape*shape);// Newly-created TypedArrays that map a SharedArrayBuffer are// marked as shared by giving them an ObjectElements that has the// ObjectElements::SHARED_MEMORY flag set.voidsetIsSharedMemory(){MOZ_ASSERT(elements_==emptyObjectElements);elements_=emptyObjectElementsShared;}inlineboolisInWholeCellBuffer()const;staticinlineJS::Result<NativeObject*,JS::OOM&>create(JSContext*cx,js::gc::AllocKindkind,js::gc::InitialHeapheap,js::HandleShapeshape,js::HandleObjectGroupgroup);protected:#ifdef DEBUGvoidcheckShapeConsistency();#elsevoidcheckShapeConsistency(){}#endifstaticShape*replaceWithNewEquivalentShape(JSContext*cx,HandleNativeObjectobj,Shape*existingShape,Shape*newShape=nullptr,boolaccessorShape=false);/* * Remove the last property of an object, provided that it is safe to do so * (the shape and previous shape do not carry conflicting information about * the object itself). */inlinevoidremoveLastProperty(JSContext*cx);inlineboolcanRemoveLastProperty();/* * Update the slot span directly for a dictionary object, and allocate * slots to cover the new span if necessary. */boolsetSlotSpan(JSContext*cx,uint32_tspan);staticMOZ_MUST_USEbooltoDictionaryMode(JSContext*cx,HandleNativeObjectobj);private:friendclassTenuringTracer;/* * Get internal pointers to the range of values starting at start and * running for length. */voidgetSlotRangeUnchecked(uint32_tstart,uint32_tlength,HeapSlot**fixedStart,HeapSlot**fixedEnd,HeapSlot**slotsStart,HeapSlot**slotsEnd){MOZ_ASSERT(start+length>=start);uint32_tfixed=numFixedSlots();if(start<fixed){if(start+length<fixed){*fixedStart=&fixedSlots()[start];*fixedEnd=&fixedSlots()[start+length];*slotsStart=*slotsEnd=nullptr;}else{uint32_tlocalCopy=fixed-start;*fixedStart=&fixedSlots()[start];*fixedEnd=&fixedSlots()[start+localCopy];*slotsStart=&slots_[0];*slotsEnd=&slots_[length-localCopy];}}else{*fixedStart=*fixedEnd=nullptr;*slotsStart=&slots_[start-fixed];*slotsEnd=&slots_[start-fixed+length];}}voidgetSlotRange(uint32_tstart,uint32_tlength,HeapSlot**fixedStart,HeapSlot**fixedEnd,HeapSlot**slotsStart,HeapSlot**slotsEnd){MOZ_ASSERT(slotInRange(start+length,SENTINEL_ALLOWED));getSlotRangeUnchecked(start,length,fixedStart,fixedEnd,slotsStart,slotsEnd);}protected:friendclassGCMarker;friendclassShape;friendclassNewObjectCache;voidinvalidateSlotRange(uint32_tstart,uint32_tlength){#ifdef DEBUGHeapSlot*fixedStart;HeapSlot*fixedEnd;HeapSlot*slotsStart;HeapSlot*slotsEnd;getSlotRange(start,length,&fixedStart,&fixedEnd,&slotsStart,&slotsEnd);Debug_SetSlotRangeToCrashOnTouch(fixedStart,fixedEnd);Debug_SetSlotRangeToCrashOnTouch(slotsStart,slotsEnd);#endif /* DEBUG */}voidinitializeSlotRange(uint32_tstart,uint32_tcount);/* * Initialize a flat array of slots to this object at a start slot. The * caller must ensure that are enough slots. */voidinitSlotRange(uint32_tstart,constValue*vector,uint32_tlength);/* * Copy a flat array of slots to this object at a start slot. Caller must * ensure there are enough slots in this object. */voidcopySlotRange(uint32_tstart,constValue*vector,uint32_tlength);#ifdef DEBUGenumSentinelAllowed{SENTINEL_NOT_ALLOWED,SENTINEL_ALLOWED};/* * Check that slot is in range for the object's allocated slots. * If sentinelAllowed then slot may equal the slot capacity. */boolslotInRange(uint32_tslot,SentinelAllowedsentinel=SENTINEL_NOT_ALLOWED)const;#endif/* * Minimum size for dynamically allocated slots in normal Objects. * ArrayObjects don't use this limit and can have a lower slot capacity, * since they normally don't have a lot of slots. */staticconstuint32_tSLOT_CAPACITY_MIN=8;HeapSlot*fixedSlots()const{returnreinterpret_cast<HeapSlot*>(uintptr_t(this)+sizeof(NativeObject));}public:staticMOZ_MUST_USEboolgenerateOwnShape(JSContext*cx,HandleNativeObjectobj,Shape*newShape=nullptr){returnreplaceWithNewEquivalentShape(cx,obj,obj->lastProperty(),newShape);}staticMOZ_MUST_USEboolshadowingShapeChange(JSContext*cx,HandleNativeObjectobj,constShape&shape);staticboolclearFlag(JSContext*cx,HandleNativeObjectobj,BaseShape::Flagflag);// The maximum number of slots in an object.// |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow// int32_t (see slotsSizeMustNotOverflow).staticconstuint32_tMAX_SLOTS_COUNT=(1<<28)-1;staticvoidslotsSizeMustNotOverflow(){static_assert(NativeObject::MAX_SLOTS_COUNT<=INT32_MAX/sizeof(JS::Value),"every caller of this method requires that a slot ""number (or slot count) count multiplied by ""sizeof(Value) can't overflow uint32_t (and sometimes ""int32_t, too)");}uint32_tnumFixedSlots()const{returnreinterpret_cast<constshadow::Object*>(this)->numFixedSlots();}uint32_tnumUsedFixedSlots()const{uint32_tnslots=lastProperty()->slotSpan(getClass());returnMin(nslots,numFixedSlots());}uint32_tnumFixedSlotsForCompilation()const;uint32_tslotSpan()const{if(inDictionaryMode())returnlastProperty()->base()->slotSpan();returnlastProperty()->slotSpan();}/* Whether a slot is at a fixed offset from this object. */boolisFixedSlot(size_tslot){returnslot<numFixedSlots();}/* Index into the dynamic slots array to use for a dynamic slot. */size_tdynamicSlotIndex(size_tslot){MOZ_ASSERT(slot>=numFixedSlots());returnslot-numFixedSlots();}/* * Grow or shrink slots immediately before changing the slot span. * The number of allocated slots is not stored explicitly, and changes to * the slots must track changes in the slot span. */boolgrowSlots(JSContext*cx,uint32_toldCount,uint32_tnewCount);voidshrinkSlots(JSContext*cx,uint32_toldCount,uint32_tnewCount);/* * This method is static because it's called from JIT code. On OOM, returns * false without leaving a pending exception on the context. */staticboolgrowSlotsDontReportOOM(JSContext*cx,NativeObject*obj,uint32_tnewCount);/* * Like growSlotsDontReportOOM but for dense elements. This will return * false if we failed to allocate a dense element for some reason (OOM, too * many dense elements, non-writable array length, etc). */staticbooladdDenseElementDontReportOOM(JSContext*cx,NativeObject*obj);boolhasDynamicSlots()const{return!!slots_;}/* Compute dynamicSlotsCount() for this object. */MOZ_ALWAYS_INLINEuint32_tnumDynamicSlots()const;boolempty()const{returnlastProperty()->isEmptyShape();}Shape*lookup(JSContext*cx,jsidid);Shape*lookup(JSContext*cx,PropertyName*name){returnlookup(cx,NameToId(name));}boolcontains(JSContext*cx,jsidid){returnlookup(cx,id)!=nullptr;}boolcontains(JSContext*cx,PropertyName*name){returnlookup(cx,name)!=nullptr;}boolcontains(JSContext*cx,Shape*shape){returnlookup(cx,shape->propid())==shape;}boolcontainsShapeOrElement(JSContext*cx,jsidid){if(JSID_IS_INT(id)&&containsDenseElement(JSID_TO_INT(id)))returntrue;returncontains(cx,id);}/* Contextless; can be called from other pure code. */Shape*lookupPure(jsidid);Shape*lookupPure(PropertyName*name){returnlookupPure(NameToId(name));}boolcontainsPure(jsidid){returnlookupPure(id)!=nullptr;}boolcontainsPure(PropertyName*name){returncontainsPure(NameToId(name));}boolcontainsPure(Shape*shape){returnlookupPure(shape->propid())==shape;}/* * Allocate and free an object slot. * * FIXME: bug 593129 -- slot allocation should be done by object methods * after calling object-parameter-free shape methods, avoiding coupling * logic across the object vs. shape module wall. */staticboolallocDictionarySlot(JSContext*cx,HandleNativeObjectobj,uint32_t*slotp);voidfreeSlot(JSContext*cx,uint32_tslot);private:staticMOZ_ALWAYS_INLINEShape*getChildProperty(JSContext*cx,HandleNativeObjectobj,HandleShapeparent,MutableHandle<StackShape>child);public:/* Add a property whose id is not yet in this scope. */staticMOZ_ALWAYS_INLINEShape*addProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,JSGetterOpgetter,JSSetterOpsetter,uint32_tslot,unsignedattrs,unsignedflags,boolallowDictionary=true);/* Add a data property whose id is not yet in this scope. */staticShape*addDataProperty(JSContext*cx,HandleNativeObjectobj,jsidid_,uint32_tslot,unsignedattrs);staticShape*addDataProperty(JSContext*cx,HandleNativeObjectobj,HandlePropertyNamename,uint32_tslot,unsignedattrs);/* Add or overwrite a property for id in this scope. */staticShape*putProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,JSGetterOpgetter,JSSetterOpsetter,uint32_tslot,unsignedattrs,unsignedflags);staticinlineShape*putProperty(JSContext*cx,HandleObjectobj,PropertyName*name,JSGetterOpgetter,JSSetterOpsetter,uint32_tslot,unsignedattrs,unsignedflags);/* Change the given property into a sibling with the same id in this scope. */staticShape*changeProperty(JSContext*cx,HandleNativeObjectobj,HandleShapeshape,unsignedattrs,JSGetterOpgetter,JSSetterOpsetter);/* Remove the property named by id from this object. */staticboolremoveProperty(JSContext*cx,HandleNativeObjectobj,jsidid);/* Clear the scope, making it empty. */staticvoidclear(JSContext*cx,HandleNativeObjectobj);protected:/* * Internal helper that adds a shape not yet mapped by this object. * * Notes: * 1. getter and setter must be normalized based on flags (see jsscope.cpp). * 2. Checks for non-extensibility must be done by callers. */staticShape*addPropertyInternal(JSContext*cx,HandleNativeObjectobj,HandleIdid,JSGetterOpgetter,JSSetterOpsetter,uint32_tslot,unsignedattrs,unsignedflags,ShapeTable::Entry*entry,boolallowDictionary,constAutoKeepShapeTables&keep);staticMOZ_MUST_USEboolfillInAfterSwap(JSContext*cx,HandleNativeObjectobj,constVector<Value>&values,void*priv);public:// Return true if this object has been converted from shared-immutable// prototype-rooted shape storage to dictionary-shapes in a doubly-linked// list.boolinDictionaryMode()const{returnlastProperty()->inDictionary();}constValue&getSlot(uint32_tslot)const{MOZ_ASSERT(slotInRange(slot));uint32_tfixed=numFixedSlots();if(slot<fixed)returnfixedSlots()[slot];returnslots_[slot-fixed];}constHeapSlot*getSlotAddressUnchecked(uint32_tslot)const{uint32_tfixed=numFixedSlots();if(slot<fixed)returnfixedSlots()+slot;returnslots_+(slot-fixed);}HeapSlot*getSlotAddressUnchecked(uint32_tslot){uint32_tfixed=numFixedSlots();if(slot<fixed)returnfixedSlots()+slot;returnslots_+(slot-fixed);}HeapSlot*getSlotAddress(uint32_tslot){/* * This can be used to get the address of the end of the slots for the * object, which may be necessary when fetching zero-length arrays of * slots (e.g. for callObjVarArray). */MOZ_ASSERT(slotInRange(slot,SENTINEL_ALLOWED));returngetSlotAddressUnchecked(slot);}constHeapSlot*getSlotAddress(uint32_tslot)const{/* * This can be used to get the address of the end of the slots for the * object, which may be necessary when fetching zero-length arrays of * slots (e.g. for callObjVarArray). */MOZ_ASSERT(slotInRange(slot,SENTINEL_ALLOWED));returngetSlotAddressUnchecked(slot);}MOZ_ALWAYS_INLINEHeapSlot&getSlotRef(uint32_tslot){MOZ_ASSERT(slotInRange(slot));return*getSlotAddress(slot);}MOZ_ALWAYS_INLINEconstHeapSlot&getSlotRef(uint32_tslot)const{MOZ_ASSERT(slotInRange(slot));return*getSlotAddress(slot);}// Check requirements on values stored to this object.MOZ_ALWAYS_INLINEvoidcheckStoredValue(constValue&v){MOZ_ASSERT(IsObjectValueInCompartment(v,compartment()));MOZ_ASSERT(AtomIsMarked(zoneFromAnyThread(),v));}MOZ_ALWAYS_INLINEvoidsetSlot(uint32_tslot,constValue&value){MOZ_ASSERT(slotInRange(slot));checkStoredValue(value);getSlotRef(slot).set(this,HeapSlot::Slot,slot,value);}MOZ_ALWAYS_INLINEvoidinitSlot(uint32_tslot,constValue&value){MOZ_ASSERT(getSlot(slot).isUndefined());MOZ_ASSERT(slotInRange(slot));checkStoredValue(value);initSlotUnchecked(slot,value);}MOZ_ALWAYS_INLINEvoidinitSlotUnchecked(uint32_tslot,constValue&value){getSlotAddressUnchecked(slot)->init(this,HeapSlot::Slot,slot,value);}// MAX_FIXED_SLOTS is the biggest number of fixed slots our GC// size classes will give an object.staticconstuint32_tMAX_FIXED_SLOTS=shadow::Object::MAX_FIXED_SLOTS;protected:MOZ_ALWAYS_INLINEboolupdateSlotsForSpan(JSContext*cx,size_toldSpan,size_tnewSpan);private:voidprepareElementRangeForOverwrite(size_tstart,size_tend){MOZ_ASSERT(end<=getDenseInitializedLength());MOZ_ASSERT(!denseElementsAreCopyOnWrite());for(size_ti=start;i<end;i++)elements_[i].HeapSlot::~HeapSlot();}/* * Trigger the write barrier on a range of slots that will no longer be * reachable. */voidprepareSlotRangeForOverwrite(size_tstart,size_tend){for(size_ti=start;i<end;i++)getSlotAddressUnchecked(i)->HeapSlot::~HeapSlot();}inlinevoidshiftDenseElementsUnchecked(uint32_tcount);public:staticboolrollbackProperties(JSContext*cx,HandleNativeObjectobj,uint32_tslotSpan);MOZ_ALWAYS_INLINEvoidsetSlotWithType(JSContext*cx,Shape*shape,constValue&value,booloverwriting=true);MOZ_ALWAYS_INLINEconstValue&getReservedSlot(uint32_tindex)const{MOZ_ASSERT(index<JSSLOT_FREE(getClass()));returngetSlot(index);}MOZ_ALWAYS_INLINEconstHeapSlot&getReservedSlotRef(uint32_tindex)const{MOZ_ASSERT(index<JSSLOT_FREE(getClass()));returngetSlotRef(index);}MOZ_ALWAYS_INLINEHeapSlot&getReservedSlotRef(uint32_tindex){MOZ_ASSERT(index<JSSLOT_FREE(getClass()));returngetSlotRef(index);}MOZ_ALWAYS_INLINEvoidinitReservedSlot(uint32_tindex,constValue&v){MOZ_ASSERT(index<JSSLOT_FREE(getClass()));initSlot(index,v);}MOZ_ALWAYS_INLINEvoidsetReservedSlot(uint32_tindex,constValue&v){MOZ_ASSERT(index<JSSLOT_FREE(getClass()));setSlot(index,v);}/* For slots which are known to always be fixed, due to the way they are allocated. */HeapSlot&getFixedSlotRef(uint32_tslot){MOZ_ASSERT(slot<numFixedSlots());returnfixedSlots()[slot];}constValue&getFixedSlot(uint32_tslot)const{MOZ_ASSERT(slot<numFixedSlots());returnfixedSlots()[slot];}voidsetFixedSlot(uint32_tslot,constValue&value){MOZ_ASSERT(slot<numFixedSlots());checkStoredValue(value);fixedSlots()[slot].set(this,HeapSlot::Slot,slot,value);}voidinitFixedSlot(uint32_tslot,constValue&value){MOZ_ASSERT(slot<numFixedSlots());checkStoredValue(value);fixedSlots()[slot].init(this,HeapSlot::Slot,slot,value);}/* * Get the number of dynamic slots to allocate to cover the properties in * an object with the given number of fixed slots and slot span. The slot * capacity is not stored explicitly, and the allocated size of the slot * array is kept in sync with this count. */staticMOZ_ALWAYS_INLINEuint32_tdynamicSlotsCount(uint32_tnfixed,uint32_tspan,constClass*clasp);staticMOZ_ALWAYS_INLINEuint32_tdynamicSlotsCount(Shape*shape);/* Elements accessors. */// The maximum size, in sizeof(Value), of the allocation used for an// object's dense elements. (This includes space used to store an// ObjectElements instance.)// |MAX_DENSE_ELEMENTS_ALLOCATION * sizeof(JS::Value)| shouldn't overflow// int32_t (see elementsSizeMustNotOverflow).staticconstuint32_tMAX_DENSE_ELEMENTS_ALLOCATION=(1<<28)-1;// The maximum number of usable dense elements in an object.staticconstuint32_tMAX_DENSE_ELEMENTS_COUNT=MAX_DENSE_ELEMENTS_ALLOCATION-ObjectElements::VALUES_PER_HEADER;staticvoidelementsSizeMustNotOverflow(){static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT<=INT32_MAX/sizeof(JS::Value),"every caller of this method require that an element ""count multiplied by sizeof(Value) can't overflow ""uint32_t (and sometimes int32_t ,too)");}ObjectElements*getElementsHeader()const{returnObjectElements::fromElements(elements_);}// Returns a pointer to the first element, including shifted elements.inlineHeapSlot*unshiftedElements()const{returnelements_-getElementsHeader()->numShiftedElements();}// Like getElementsHeader, but returns a pointer to the unshifted header.// This is mainly useful for free()ing dynamic elements: the pointer// returned here is the one we got from malloc.void*getUnshiftedElementsHeader()const{returnObjectElements::fromElements(unshiftedElements());}uint32_tunshiftedIndex(uint32_tindex)const{returnindex+getElementsHeader()->numShiftedElements();}/* Accessors for elements. */boolensureElements(JSContext*cx,uint32_tcapacity){MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());if(capacity>getDenseCapacity())returngrowElements(cx,capacity);returntrue;}// Try to shift |count| dense elements, see the "Shifted elements" comment.inlinebooltryShiftDenseElements(uint32_tcount);// Try to make space for |count| dense elements at the start of the array.booltryUnshiftDenseElements(uint32_tcount);// Move the elements header and all shifted elements to the start of the// allocated elements space, so that numShiftedElements is 0 afterwards.voidmoveShiftedElements();// If this object has many shifted elements call moveShiftedElements.voidmaybeMoveShiftedElements();staticboolgoodElementsAllocationAmount(JSContext*cx,uint32_treqAllocated,uint32_tlength,uint32_t*goodAmount);boolgrowElements(JSContext*cx,uint32_tnewcap);voidshrinkElements(JSContext*cx,uint32_tcap);voidsetDynamicElements(ObjectElements*header){MOZ_ASSERT(!hasDynamicElements());elements_=header->elements();MOZ_ASSERT(hasDynamicElements());}staticboolCopyElementsForWrite(JSContext*cx,NativeObject*obj);boolmaybeCopyElementsForWrite(JSContext*cx){if(denseElementsAreCopyOnWrite())returnCopyElementsForWrite(cx,this);returntrue;}private:inlinevoidensureDenseInitializedLengthNoPackedCheck(JSContext*cx,uint32_tindex,uint32_textra);// Run a post write barrier that encompasses multiple contiguous elements in a// single step.inlinevoidelementsRangeWriteBarrierPost(uint32_tstart,uint32_tcount);// See the comment over setDenseElementUnchecked, this applies in the same way.voidsetDenseInitializedLengthUnchecked(uint32_tlength){MOZ_ASSERT(length<=getDenseCapacity());MOZ_ASSERT(!denseElementsAreCopyOnWrite());prepareElementRangeForOverwrite(length,getElementsHeader()->initializedLength);getElementsHeader()->initializedLength=length;}// Use this function with care. This is done to allow sparsifying frozen// objects, but should only be called in a few places, and should be// audited carefully!voidsetDenseElementUnchecked(uint32_tindex,constValue&val){MOZ_ASSERT(index<getDenseInitializedLength());MOZ_ASSERT(!denseElementsAreCopyOnWrite());checkStoredValue(val);elements_[index].set(this,HeapSlot::Element,unshiftedIndex(index),val);}public:voidsetDenseInitializedLength(uint32_tlength){MOZ_ASSERT(!denseElementsAreFrozen());setDenseInitializedLengthUnchecked(length);}inlinevoidensureDenseInitializedLength(JSContext*cx,uint32_tindex,uint32_textra);voidsetDenseElement(uint32_tindex,constValue&val){MOZ_ASSERT(!denseElementsAreFrozen());setDenseElementUnchecked(index,val);}voidinitDenseElement(uint32_tindex,constValue&val){MOZ_ASSERT(index<getDenseInitializedLength());MOZ_ASSERT(!denseElementsAreCopyOnWrite());MOZ_ASSERT(!denseElementsAreFrozen());checkStoredValue(val);elements_[index].init(this,HeapSlot::Element,unshiftedIndex(index),val);}voidsetDenseElementMaybeConvertDouble(uint32_tindex,constValue&val){if(val.isInt32()&&shouldConvertDoubleElements())setDenseElement(index,DoubleValue(val.toInt32()));elsesetDenseElement(index,val);}inlinevoidsetDenseElementWithType(JSContext*cx,uint32_tindex,constValue&val);inlinevoidinitDenseElementWithType(JSContext*cx,uint32_tindex,constValue&val);inlinevoidsetDenseElementHole(JSContext*cx,uint32_tindex);staticinlinevoidremoveDenseElementForSparseIndex(JSContext*cx,HandleNativeObjectobj,uint32_tindex);inlineValuegetDenseOrTypedArrayElement(uint32_tidx);inlinevoidcopyDenseElements(uint32_tdstStart,constValue*src,uint32_tcount);inlinevoidinitDenseElements(uint32_tdstStart,constValue*src,uint32_tcount);inlinevoidmoveDenseElements(uint32_tdstStart,uint32_tsrcStart,uint32_tcount);inlinevoidmoveDenseElementsNoPreBarrier(uint32_tdstStart,uint32_tsrcStart,uint32_tcount);boolshouldConvertDoubleElements(){returngetElementsHeader()->shouldConvertDoubleElements();}inlinevoidsetShouldConvertDoubleElements();inlinevoidclearShouldConvertDoubleElements();booldenseElementsAreCopyOnWrite(){returngetElementsHeader()->isCopyOnWrite();}booldenseElementsAreFrozen(){returngetElementsHeader()->isFrozen();}/* Packed information for this object's elements. */inlineboolwriteToIndexWouldMarkNotPacked(uint32_tindex);inlinevoidmarkDenseElementsNotPacked(JSContext*cx);// Ensures that the object can hold at least index + extra elements. This// returns DenseElement_Success on success, DenseElement_Failed on failure// to grow the array, or DenseElement_Incomplete when the object is too// sparse to grow (this includes the case of index + extra overflow). In// the last two cases the object is kept intact.inlineDenseElementResultensureDenseElements(JSContext*cx,uint32_tindex,uint32_textra);inlineDenseElementResultextendDenseElements(JSContext*cx,uint32_trequiredCapacity,uint32_textra);/* Convert a single dense element to a sparse property. */staticboolsparsifyDenseElement(JSContext*cx,HandleNativeObjectobj,uint32_tindex);/* Convert all dense elements to sparse properties. */staticboolsparsifyDenseElements(JSContext*cx,HandleNativeObjectobj);/* Small objects are dense, no matter what. */staticconstuint32_tMIN_SPARSE_INDEX=1000;/* * Element storage for an object will be sparse if fewer than 1/8 indexes * are filled in. */staticconstunsignedSPARSE_DENSITY_RATIO=8;/* * Check if after growing the object's elements will be too sparse. * newElementsHint is an estimated number of elements to be added. */boolwillBeSparseElements(uint32_trequiredCapacity,uint32_tnewElementsHint);/* * After adding a sparse index to obj, see if it should be converted to use * dense elements. */staticDenseElementResultmaybeDensifySparseElements(JSContext*cx,HandleNativeObjectobj);inlineHeapSlot*fixedElements()const{static_assert(2*sizeof(Value)==sizeof(ObjectElements),"when elements are stored inline, the first two ""slots will hold the ObjectElements header");return&fixedSlots()[2];}#ifdef DEBUGboolcanHaveNonEmptyElements();#endifvoidsetFixedElements(uint32_tnumShifted=0){MOZ_ASSERT(canHaveNonEmptyElements());elements_=fixedElements()+numShifted;}inlineboolhasDynamicElements()const{/* * Note: for objects with zero fixed slots this could potentially give * a spurious 'true' result, if the end of this object is exactly * aligned with the end of its arena and dynamic slots are allocated * immediately afterwards. Such cases cannot occur for dense arrays * (which have at least two fixed slots) and can only result in a leak. */return!hasEmptyElements()&&!hasFixedElements();}inlineboolhasFixedElements()const{returnunshiftedElements()==fixedElements();}inlineboolhasEmptyElements()const{returnelements_==emptyObjectElements||elements_==emptyObjectElementsShared;}/* * Get a pointer to the unused data in the object's allocation immediately * following this object, for use with objects which allocate a larger size * class than they need and store non-elements data inline. */inlineuint8_t*fixedData(size_tnslots)const;inlinevoidprivateWriteBarrierPre(void**oldval);voidprivateWriteBarrierPost(void**pprivate){gc::Cell**cellp=reinterpret_cast<gc::Cell**>(pprivate);MOZ_ASSERT(cellp);MOZ_ASSERT(*cellp);gc::StoreBuffer*storeBuffer=(*cellp)->storeBuffer();if(storeBuffer)storeBuffer->putCell(cellp);}/* Private data accessors. */inlinevoid*&privateRef(uint32_tnfixed)const{/* XXX should be private, not protected! *//* * The private pointer of an object can hold any word sized value. * Private pointers are stored immediately after the last fixed slot of * the object. */MOZ_ASSERT(nfixed==numFixedSlots());MOZ_ASSERT(hasPrivate());HeapSlot*end=&fixedSlots()[nfixed];return*reinterpret_cast<void**>(end);}boolhasPrivate()const{returngetClass()->hasPrivate();}void*getPrivate()const{returnprivateRef(numFixedSlots());}voidsetPrivate(void*data){void**pprivate=&privateRef(numFixedSlots());privateWriteBarrierPre(pprivate);*pprivate=data;}voidsetPrivateGCThing(gc::Cell*cell){MOZ_ASSERT_IF(IsMarkedBlack(this),!JS::GCThingIsMarkedGray(JS::GCCellPtr(cell,cell->getTraceKind())));void**pprivate=&privateRef(numFixedSlots());privateWriteBarrierPre(pprivate);*pprivate=reinterpret_cast<void*>(cell);privateWriteBarrierPost(pprivate);}voidsetPrivateUnbarriered(void*data){void**pprivate=&privateRef(numFixedSlots());*pprivate=data;}voidinitPrivate(void*data){privateRef(numFixedSlots())=data;}/* Access private data for an object with a known number of fixed slots. */inlinevoid*getPrivate(uint32_tnfixed)const{returnprivateRef(nfixed);}staticinlineNativeObject*copy(JSContext*cx,gc::AllocKindkind,gc::InitialHeapheap,HandleNativeObjecttemplateObject);voidupdateShapeAfterMovingGC();voidsweepDictionaryListPointer();/* JIT Accessors */staticsize_toffsetOfElements(){returnoffsetof(NativeObject,elements_);}staticsize_toffsetOfFixedElements(){returnsizeof(NativeObject)+sizeof(ObjectElements);}staticsize_tgetFixedSlotOffset(size_tslot){returnsizeof(NativeObject)+slot*sizeof(Value);}staticsize_tgetPrivateDataOffset(size_tnfixed){returngetFixedSlotOffset(nfixed);}staticsize_toffsetOfSlots(){returnoffsetof(NativeObject,slots_);}};// Object class for plain native objects created using '{}' object literals,// 'new Object()', 'Object.create', etc.classPlainObject:publicNativeObject{public:staticconstjs::Classclass_;};inlinevoidNativeObject::privateWriteBarrierPre(void**oldval){JS::shadow::Zone*shadowZone=this->shadowZoneFromAnyThread();if(shadowZone->needsIncrementalBarrier()&&*oldval&&getClass()->hasTrace())getClass()->doTrace(shadowZone->barrierTracer(),this);}/*** Standard internal methods *******************************************************************//* * These functions should follow the algorithms in ES6 draft rev 29 section 9.1 * ("Ordinary Object Internal Methods"). It's an ongoing project. * * Many native objects are not "ordinary" in ES6, so these functions also have * to serve some of the special needs of Functions (9.2, 9.3, 9.4.1), Arrays * (9.4.2), Strings (9.4.3), and so on. */externboolNativeDefineProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,Handle<JS::PropertyDescriptor>desc,ObjectOpResult&result);externboolNativeDefineProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,HandleValuevalue,JSGetterOpgetter,JSSetterOpsetter,unsignedattrs,ObjectOpResult&result);externboolNativeDefineProperty(JSContext*cx,HandleNativeObjectobj,PropertyName*name,HandleValuevalue,GetterOpgetter,SetterOpsetter,unsignedattrs,ObjectOpResult&result);externboolNativeDefineElement(JSContext*cx,HandleNativeObjectobj,uint32_tindex,HandleValuevalue,JSGetterOpgetter,JSSetterOpsetter,unsignedattrs,ObjectOpResult&result);/* If the result out-param is omitted, throw on failure. */externboolNativeDefineProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,HandleValuevalue,JSGetterOpgetter,JSSetterOpsetter,unsignedattrs);externboolNativeDefineProperty(JSContext*cx,HandleNativeObjectobj,PropertyName*name,HandleValuevalue,JSGetterOpgetter,JSSetterOpsetter,unsignedattrs);externboolNativeHasProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,bool*foundp);externboolNativeGetOwnPropertyDescriptor(JSContext*cx,HandleNativeObjectobj,HandleIdid,MutableHandle<JS::PropertyDescriptor>desc);externboolNativeGetProperty(JSContext*cx,HandleNativeObjectobj,HandleValuereceiver,HandleIdid,MutableHandleValuevp);externboolNativeGetPropertyNoGC(JSContext*cx,NativeObject*obj,constValue&receiver,jsidid,Value*vp);inlineboolNativeGetProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,MutableHandleValuevp){RootedValuereceiver(cx,ObjectValue(*obj));returnNativeGetProperty(cx,obj,receiver,id,vp);}boolSetPropertyByDefining(JSContext*cx,HandleIdid,HandleValuev,HandleValuereceiver,ObjectOpResult&result);boolSetPropertyOnProto(JSContext*cx,HandleObjectobj,HandleIdid,HandleValuev,HandleValuereceiver,ObjectOpResult&result);/* * Indicates whether an assignment operation is qualified (`x.y = 0`) or * unqualified (`y = 0`). In strict mode, the latter is an error if no such * variable already exists. * * Used as an argument to NativeSetProperty. */enumQualifiedBool{Unqualified=0,Qualified=1};externboolNativeSetProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,HandleValuev,HandleValuereceiver,QualifiedBoolqualified,ObjectOpResult&result);externboolNativeSetElement(JSContext*cx,HandleNativeObjectobj,uint32_tindex,HandleValuev,HandleValuereceiver,ObjectOpResult&result);externboolNativeDeleteProperty(JSContext*cx,HandleNativeObjectobj,HandleIdid,ObjectOpResult&result);/*** SpiderMonkey nonstandard internal methods ***************************************************/template<AllowGCallowGC>externboolNativeLookupOwnProperty(JSContext*cx,typenameMaybeRooted<NativeObject*,allowGC>::HandleTypeobj,typenameMaybeRooted<jsid,allowGC>::HandleTypeid,typenameMaybeRooted<PropertyResult,allowGC>::MutableHandleTypepropp);/* * Get a property from `receiver`, after having already done a lookup and found * the property on a native object `obj`. * * `shape` must not be null and must not be an implicit dense property. It must * be present in obj's shape chain. */externboolNativeGetExistingProperty(JSContext*cx,HandleObjectreceiver,HandleNativeObjectobj,HandleShapeshape,MutableHandleValuevp);/* * */externboolGetNameBoundInEnvironment(JSContext*cx,HandleObjectenv,HandleIdid,MutableHandleValuevp);}/* namespace js */template<>inlineboolJSObject::is<js::NativeObject>()const{returnisNative();}namespacejs{// Alternate to JSObject::as<NativeObject>() that tolerates null pointers.inlineNativeObject*MaybeNativeObject(JSObject*obj){returnobj?&obj->as<NativeObject>():nullptr;}// Defined in NativeObject-inl.h.boolIsPackedArray(JSObject*obj);externvoidAddPropertyTypesAfterProtoChange(JSContext*cx,NativeObject*obj,ObjectGroup*oldGroup);}// namespace js/*** Inline functions declared in jsobj.h that use the native declarations above *****************/inlinebooljs::HasProperty(JSContext*cx,HandleObjectobj,HandleIdid,bool*foundp){if(HasPropertyOpop=obj->getOpsHasProperty())returnop(cx,obj,id,foundp);returnNativeHasProperty(cx,obj.as<NativeObject>(),id,foundp);}inlinebooljs::GetProperty(JSContext*cx,HandleObjectobj,HandleValuereceiver,HandleIdid,MutableHandleValuevp){if(GetPropertyOpop=obj->getOpsGetProperty())returnop(cx,obj,receiver,id,vp);returnNativeGetProperty(cx,obj.as<NativeObject>(),receiver,id,vp);}inlinebooljs::GetPropertyNoGC(JSContext*cx,JSObject*obj,constValue&receiver,jsidid,Value*vp){if(obj->getOpsGetProperty())returnfalse;returnNativeGetPropertyNoGC(cx,&obj->as<NativeObject>(),receiver,id,vp);}inlinebooljs::SetProperty(JSContext*cx,HandleObjectobj,HandleIdid,HandleValuev,HandleValuereceiver,ObjectOpResult&result){if(obj->getOpsSetProperty())returnJSObject::nonNativeSetProperty(cx,obj,id,v,receiver,result);returnNativeSetProperty(cx,obj.as<NativeObject>(),id,v,receiver,Qualified,result);}inlinebooljs::SetElement(JSContext*cx,HandleObjectobj,uint32_tindex,HandleValuev,HandleValuereceiver,ObjectOpResult&result){if(obj->getOpsSetProperty())returnJSObject::nonNativeSetElement(cx,obj,index,v,receiver,result);returnNativeSetElement(cx,obj.as<NativeObject>(),index,v,receiver,result);}#endif /* vm_NativeObject_h */